#include "am_cpu_test.h"

char COLOR_RED[]   = "\033[1;31m";
char COLOR_GREEN[] = "\033[1;32m";
char COLOR_NONE[]  = "\033[0m";

#define check(cond) if(!cond) return 1;
#define LENGTH (sizeof(arr) / sizeof((arr)[0]))

void cpu_test()
{
    if(!to_lower_case_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "to-lower-case", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "to-lower-case", COLOR_RED, COLOR_NONE);
    }
    if(!div_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "div", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "div", COLOR_RED, COLOR_NONE);
    }
    if(!quick_sort_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "quick-sort", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "quick-sort", COLOR_RED, COLOR_NONE);
    }
    if(!shuixianhua_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "shuixianhua", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "shuixianhua", COLOR_RED, COLOR_NONE);
    }
    if(!recursion_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "recursion", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "recursion", COLOR_RED, COLOR_NONE);
    }
    if(!wanshu_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "wanshu", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "wanshu", COLOR_RED, COLOR_NONE);
    }
    if(!bubble_sort_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "bubble-sort", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "bubble-sort", COLOR_RED, COLOR_NONE);
    }
    if(!fib_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "fib", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "fib", COLOR_RED, COLOR_NONE);
    }
    if(!sub_longlong_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "sub-longlong", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "sub-longlong", COLOR_RED, COLOR_NONE);
    }
    if(!min3_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "min3", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "min3", COLOR_RED, COLOR_NONE);
    }
    if(!dummy_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "dummy", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "dummy", COLOR_RED, COLOR_NONE);
    }
    if(!movsx_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "movsx", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "movsx", COLOR_RED, COLOR_NONE);
    }
    if(!matrix_mul_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "matrix-mul", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "matrix-mul", COLOR_RED, COLOR_NONE);
    }
    if(!shift_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "shift", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "shift", COLOR_RED, COLOR_NONE);
    }
    if(!max_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "max", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "max", COLOR_RED, COLOR_NONE);
    }
    if(!mov_c_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "mov-c", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "mov-c", COLOR_RED, COLOR_NONE);
    }
    if(!unalign_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "unalign", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "unalign", COLOR_RED, COLOR_NONE);
    }
    if(!select_sort_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "select-sort", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "select-sort", COLOR_RED, COLOR_NONE);
    }
    if(!mul_longlong_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "mul-longlong", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "mul-longlong", COLOR_RED, COLOR_NONE);
    }
    if(!load_store_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "load-store", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "load-store", COLOR_RED, COLOR_NONE);
    }
    if(!fact_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "fact", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "fact", COLOR_RED, COLOR_NONE);
    }
    if(!prime_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "prime", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "prime", COLOR_RED, COLOR_NONE);
    }
    if(!pascal_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "pascal", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "pascal", COLOR_RED, COLOR_NONE);
    }
    if(!string_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "string", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "string", COLOR_RED, COLOR_NONE);
    }
    if(!add_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "add", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "add", COLOR_RED, COLOR_NONE);
    }
    if(!bit_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "bit", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "bit", COLOR_RED, COLOR_NONE);
    }
    if(!add_longlong_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "add-longlong", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "add-longlong", COLOR_RED, COLOR_NONE);
    }
    if(!hello_str_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "hello-str", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "hello-str", COLOR_RED, COLOR_NONE);
    }
    if(!switch_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "switch", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "switch", COLOR_RED, COLOR_NONE);
    }
    if(!leap_year_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "leap-year", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "leap-year", COLOR_RED, COLOR_NONE);
    }
    if(!goldbach_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "goldbach", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "goldbach", COLOR_RED, COLOR_NONE);
    }
    if(!sum_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "sum", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "sum", COLOR_RED, COLOR_NONE);
    }
    if(!if_else_main())
    {
        rt_kprintf("[%14s] %sPASS!%s\n", "if-else", COLOR_GREEN, COLOR_NONE);
    }
    else
    {
        rt_kprintf("[%14s] %sFAIL!%s\n", "if-else", COLOR_RED, COLOR_NONE);
    }
}

// to_lower_case_

char to_lower_case_to_lower_case(char c) {
	return (c >= 'A' && c <= 'Z' ? (c + 32) : c);
}

volatile char to_lower_case_ans [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
	97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
	91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127};

int to_lower_case_main() {
	int i;
	for(i = 0; i < 128; i ++) {
		check(to_lower_case_to_lower_case(i) == to_lower_case_ans[i]);
	}

	return 0;
}
// div_

#define div_N 10
int div_a[div_N];

int div_main() {
  int i, j;
  for(i = 0; i < div_N; i ++)
    div_a[i] = i;
  for(i = 0; i < div_N; i ++)
    for(j = 1; j < div_N + 1; j ++)
      div_a[i] *= j;
  for(i = 0; i < div_N; i ++)
    for(j = 1; j < div_N + 1; j ++)
      div_a[i] /= j;

  for(i = 0; i < div_N; i ++)
    check(div_a[i] == i);

  return 0;
}
// quick_sort_

#define quick_sort_N 20

int quick_sort_a[quick_sort_N] = {2, 12, 14, 6, 13, 15, 16, 10, 0, 18, 11, 19, 9, 1, 7, 5, 4, 3, 8, 17};

int quick_sort_partition(int *a, int p, int q) {
	int pivot = a[p];
	int i = p, j = q;
	while(i < j) {
		while(i < j && a[j] > pivot) j --;
		a[i] = a[j];

		while(i < j && a[i] <= pivot) i ++;
		a[j] = a[i];
	}

	a[i] = pivot;
	return i;
}

void quick_sort_quick_sort(int *a, int p, int q) {
	if(p >= q) return;

	int m = partition(a, p, q);
	quick_sort(a, p, m - 1);
	quick_sort(a, m + 1, q);
}

int quick_sort_main() {
	quick_sort(quick_sort_a, 0, quick_sort_N - 1);

	int i;
	for(i = 0; i < quick_sort_N; i ++) {
		check(quick_sort_a[i] == i);
	}

	check(i == quick_sort_N);

	quick_sort(quick_sort_a, 0, quick_sort_N - 1);

	for(i = 0; i < quick_sort_N; i ++) {
		check(quick_sort_a[i] == i);
	}

	check(i == quick_sort_N);

	return 0;
}
// shuixianhua_

int shuixianhua_ans[] = {153, 370, 371, 407};

int shuixianhua_cube(int n) {
	return n * n * n;
}

int shuixianhua_main() {
	int n, n2, n1, n0;
	int k = 0;
	for(n = 100; n < 500; n ++) {
		n2 = n / 100;
		n1 = (n / 10) % 10;
		n0 = n % 10;

		if(n == shuixianhua_cube(n2) + shuixianhua_cube(n1) + shuixianhua_cube(n0)) {
			check(n == shuixianhua_ans[k]);
			k ++;
		}
	}

	check(k == 4);

	return 0;
}
// recursion_

int recursion_f0(int, int);
int recursion_f1(int, int);
int recursion_f2(int, int);
int recursion_f3(int, int);

int (*func[])(int, int) = {
  recursion_f0, recursion_f1, recursion_f2, recursion_f3,
};

int recursion_rec = 0, recursion_lvl = 0;

int recursion_f0(int n, int l) {
  if (l > recursion_lvl) recursion_lvl = l;
  recursion_rec ++;
  return n <= 0 ? 1 : func[3](n / 3, l + 1);
};

int recursion_f1(int n, int l) {
  if (l > recursion_lvl) recursion_lvl = l;
  recursion_rec ++;
  return n <= 0 ? 1 : func[0](n - 1, l + 1);
};

int recursion_f2(int n, int l) {
  if (l > recursion_lvl) recursion_lvl = l;
  recursion_rec ++;
  return n <= 0 ? 1 : func[1](n, l + 1) + 9;
};

int recursion_f3(int n, int l) {
  if (l > recursion_lvl) recursion_lvl = l;
  recursion_rec ++;
  return n <= 0 ? 1 : func[2](n / 2, l + 1) * 3 + func[2](n / 2, l + 1) * 2;
};

int recursion_ans[] = {38270, 218, 20};

int recursion_main() {
  int x = func[0](14371, 0);
  check(x == recursion_ans[0]);   // answer
  check(recursion_rec == recursion_ans[1]); // # recursions
  check(recursion_lvl == recursion_ans[2]); // max depth
  return 0;
}
// wanshu_

int wanshu_ans[] = {6, 28};

int wanshu_main() {
	int n, sum, i, k = 0;
	for(n = 1; n < 30; n ++) {
		sum = 0;
		for(i = 1; i < n; i ++) {
			if(n % i == 0) {
				sum += i;
			}
		}

		if(sum == n) {
			check(n == wanshu_ans[k]);
			k ++;
		}
	}

	check(k == 2);

	return 0;
}
// bubble_sort_

#define bubble_sort_N 20

int bubble_sort_a[bubble_sort_N] = {2, 12, 14, 6, 13, 15, 16, 10, 0, 18, 11, 19, 9, 1, 7, 5, 4, 3, 8, 17};

void bubble_sort_bubble_sort() {
	int i, j, t;
	for(j = 0; j < bubble_sort_N; j ++) {
		for(i = 0; i < bubble_sort_N - 1 - j; i ++) {
			if(bubble_sort_a[i] > bubble_sort_a[i + 1]) {
				t = bubble_sort_a[i];
				bubble_sort_a[i] = bubble_sort_a[i + 1];
				bubble_sort_a[i + 1] = t;
			}
		}
	}
}

int bubble_sort_main() {
	bubble_sort_bubble_sort();

	int i;
	for(i = 0; i < bubble_sort_N; i ++) {
		check(bubble_sort_a[i] == i);
	}

	check(i == bubble_sort_N);

	bubble_sort_bubble_sort();

	for(i = 0; i < bubble_sort_N; i ++) {
		check(bubble_sort_a[i] == i);
	}

	check(i == bubble_sort_N);

	return 0;
}
// fib_

int fib_fib[40] = {1, 1};
int fib_ans[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155};

int fib_main() {
	int i;
	for(i = 2; i < 40; i ++) {
		fib_fib[i] = fib_fib[i - 1] + fib_fib[i - 2];
		check(fib_fib[i] == fib_ans[i]);
	}

	check(i == 40);

	return 0;
}
// sub_longlong_

long long sub_longlong_sub(long long a, long long b) {
	long long c = a - b;
	return c;
}

long long sub_longlong_test_data[] = {0, 1, 2, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL};
long long sub_longlong_ans[] = {0LL, 0xffffffffffffffffLL, 0xfffffffffffffffeLL, 0x8000000000000001LL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x2LL, 0x1LL, 0x1LL, 0LL, 0xffffffffffffffffLL, 0x8000000000000002LL, 0x8000000000000001LL, 0x8000000000000000LL, 0x3LL, 0x2LL, 0x2LL, 0x1LL, 0LL, 0x8000000000000003LL, 0x8000000000000002LL, 0x8000000000000001LL, 0x4LL, 0x3LL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x7ffffffffffffffdLL, 0LL, 0xffffffffffffffffLL, 0xfffffffffffffffeLL, 0x8000000000000001LL, 0x8000000000000000LL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x1LL, 0LL, 0xffffffffffffffffLL, 0x8000000000000002LL, 0x8000000000000001LL, 0x8000000000000001LL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x2LL, 0x1LL, 0LL, 0x8000000000000003LL, 0x8000000000000002LL, 0xfffffffffffffffeLL, 0xfffffffffffffffdLL, 0xfffffffffffffffcLL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x7ffffffffffffffdLL, 0LL, 0xffffffffffffffffLL, 0xffffffffffffffffLL, 0xfffffffffffffffeLL, 0xfffffffffffffffdLL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x1LL, 0LL};

#define sub_longlong_NR_DATA LENGTH(test_data)

int sub_longlong_main() {
	int i, j, ans_idx = 0;
	for(i = 0; i < sub_longlong_NR_DATA; i ++) {
		for(j = 0; j < sub_longlong_NR_DATA; j ++) {
			check(sub(sub_longlong_test_data[i], sub_longlong_test_data[j]) == sub_longlong_ans[ans_idx ++]);
		}
	}

	return 0;
}
// min3_

int min3_min3(int x, int y, int z) {
	int m;
	if(x < y) { m = x; }
	else { m = y; }
	if(z < m) m = z;
	return m;
}

int min3_test_data[] = {0, 0x7fffffff, 0x80000000, 0xffffffff};
int min3_ans [] = {0, 0, -2147483648, -1, 0, 0, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1, 0, 0, -2147483648, -1, 0, 2147483647, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1, -1, -1, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1};

#define min3_NR_DATA LENGTH(test_data)

int min3_main() {
	int i, j, k, ans_idx = 0;
	for(i = 0; i < min3_NR_DATA; i ++) {
		for(j = 0; j < min3_NR_DATA; j ++) {
			for(k = 0; k < min3_NR_DATA; k ++) {
				check(min3_min3(min3_test_data[i], min3_test_data[j], min3_test_data[k]) == min3_ans[ans_idx ++]);
			}
			check(k == min3_NR_DATA);
		}
		check(j == min3_NR_DATA);
	}

	check(i == min3_NR_DATA);

	return 0;
}

int dummy_main() {
  return 0;
}
// movsx_

volatile int movsx_A[10];
volatile int movsx_b;
volatile signed char movsx_C[10];
int movsx_main() {
	movsx_A[0] = 0;
	movsx_A[1] = 1;
	movsx_A[2] = 2;
	movsx_A[3] = 3;
	movsx_A[4] = 4;

	movsx_b = movsx_A[3];
	movsx_A[5] = movsx_b;
	movsx_C[0] = 'a';
	check(movsx_C[0] == 'a');
	movsx_C[1] = movsx_C[0];
	check(movsx_C[1] == 'a');
	movsx_A[0] = (int)movsx_C[0];
	check(movsx_A[0] == 'a');
	movsx_C[1] = 0x80;
	movsx_A[0] = (int)movsx_C[1];
	check(movsx_A[1] == 1);
	check(movsx_A[2] == 2);
	check(movsx_A[3] == 3);
	check(movsx_A[4] == 4);
	check(movsx_b == 3);
	check(movsx_A[5] == 3);
	check(movsx_C[1] == 0xffffff80);
	check(movsx_A[0] == 0xffffff80);

	return 0;
}
// matrix_mul_

#define matrix_mul_N 10
int matrix_mul_a[matrix_mul_N][matrix_mul_N] = {
{31, -73, -67, -28, 87, -17, -15, -35, -53, -54},
{52, 36, 9, -91, -27, -78, 42, 82, 19, -6},
{41, -56, 31, 32, -52, 74, 28, 20, 55, -72},
{-59, 2, -79, -8, 44, 55, -83, -95, -45, 50},
{-95, 61, -63, 62, -16, 52, 40, 92, -32, -26},
{-99, 52, 96, 63, -75, -74, -82, 82, -95, 42},
{11, -22, 27, -27, -27, -76, -71, 58, -40, -65},
{91, -53, -67, 72, 36, -77, -3, 93, -24, 97},
{-52, -11, -77, -93, -92, -24, 70, 18, 56, 88},
{-43, -41, -26, 11, -84, -14, -41, 83, 27, -11}
};
int matrix_mul_b[matrix_mul_N][matrix_mul_N] = {
	{-48, -70, -40, -82, -74, -63, -59, -72, -100, -72},
{5, -84, 28, 56, 60, -33, -42, -50, -83, -83},
{-5, 5, 48, 75, -78, -9, 9, 2, 88, 70},
{69, 23, 66, 66, -11, 50, 67, 18, -58, 76},
{30, 45, 32, 25, -73, 57, -67, -14, 53, -33},
{98, -86, -63, 80, -45, -88, 80, -64, 58, -84},
{-55, -39, -13, -27, -37, 8, -96, 84, -89, 31},
{-82, 58, 81, -41, -58, 36, 76, -79, -29, 23},
{86, -46, 16, -18, 81, 90, 35, -90, 43, 55},
{-38, -19, -40, 82, -76, 57, -29, -2, 79, -48},
};

int matrix_mul_ans[matrix_mul_N][matrix_mul_N] = {
	{-1317, 10379, -5821, -14322, -4330, -3114, -9940, 7033, -1883, -6027},
	{-24266, -861, 4044, -19824, -223, 886, -11988, -6442, -13846, -1054},
	{9783, -7073, -918, -5911, -967, -7100, 14605, -7556, -3439, 9607},
	{15980, -520, -13297, 15043, 6185, -3654, 1325, 4193, 16925, -17761},
	{2566, 3187, 10248, 7925, 6318, 1421, 14648, 700, -12193, 1083},
	{-12603, 19006, 20952, 18599, -1539, 5184, 17408, 6740, 6264, 15114},
	{-12715, 15121, 9963, -13717, 2411, -2196, 6147, -1698, -3389, 8200},
	{-19007, 12417, 5723, -11309, -19242, 15740, -3791, -3949, -13130, -21},
	{-12557, -5970, -11570, -8905, 12227, 7814, -5094, 4532, 1071, -1309},
	{-2955, 9381, 6372, -6898, 9117, 5753, 20778, -5045, 1047, 12114}};

int matrix_mul_c[matrix_mul_N][matrix_mul_N];

int matrix_mul_main() {
	int i, j, k;
	for(i = 0; i < matrix_mul_N; i ++) {
		for(j = 0; j < matrix_mul_N; j ++) {
			matrix_mul_c[i][j] = 0;
			for(k = 0; k < matrix_mul_N; k ++) {
				matrix_mul_c[i][j] += matrix_mul_a[i][k] * matrix_mul_b[k][j];
			}
			check(matrix_mul_c[i][j] == matrix_mul_ans[i][j]);
			check(k == matrix_mul_N);
		}
		check(j == matrix_mul_N);
	}

	check(i == matrix_mul_N);

	return 0;
}
// shift_

unsigned shift_test[] = {
	0x12345678, 0x98765432, 0x0, 0xeffa1000, 0x7fffffff, 0x80000000, 0x33, 0xffffffff
};

unsigned shift_srl_ans[] = {
	0x2468ac, 0x130eca8, 0x0, 0x1dff420, 0xffffff, 0x1000000, 0x0, 0x1ffffff
};

unsigned shift_srlv_ans[] = {
	0x1234567, 0x4c3b2a1, 0x0, 0x1dff420, 0x7fffff, 0x400000, 0x0, 0x1fffff
};

unsigned shift_srav_ans[] = {
	0x1234567, 0xfcc3b2a1, 0x0, 0xffdff420, 0x7fffff, 0xffc00000, 0x0, 0xffffffff
};


int shift_main() {
	unsigned i;

	for(i = 0; i < LENGTH(shift_test); i ++) {
		check((shift_test[i] >> 7) == shift_srl_ans[i]);
	}

	for(i = 0; i < LENGTH(shift_test); i ++) {
		check((unsigned)((int)shift_test[i] >> (i + 4)) == shift_srav_ans[i]);
	}

	for(i = 0; i < LENGTH(shift_test); i ++) {
		check((shift_test[i] >> (i + 4)) == shift_srlv_ans[i]);
	}

	return 0;
}
// max_

int max_max(int x, int y) {
	int z;
	if(x > y) { z = x; }
	else { z = y; }
	return z;
}

int max_test_data[] = {0, 1, 2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff};
int max_ans[] = {0, 0x1, 0x2, 0x7fffffff, 0, 0, 0, 0, 0x1, 0x1, 0x2, 0x7fffffff, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x7fffffff, 0x2, 0x2, 0x2, 0x2, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0, 0x1, 0x2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff, 0, 0x1, 0x2, 0x7fffffff, 0x80000001, 0x80000001, 0xfffffffe, 0xffffffff, 0, 0x1, 0x2, 0x7fffffff, 0xfffffffe, 0xfffffffe, 0xfffffffe, 0xffffffff, 0, 0x1, 0x2, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};

#define max_NR_DATA LENGTH(max_test_data)

int max_main() {
	int i, j, ans_idx = 0;
	for(i = 0; i < max_NR_DATA; i ++) {
		for(j = 0; j < max_NR_DATA; j ++) {
			check(max(max_test_data[i], max_test_data[j]) == max_ans[ans_idx ++]);
		}
		check(j == max_NR_DATA);
	}

	check(i == max_NR_DATA);

	return 0;
}
// mov_c_

volatile int mov_c_A[10];
volatile int mov_c_b;

int mov_c_main() {
	mov_c_A[0] = 0;
	mov_c_A[1] = 1;
	mov_c_A[2] = 2;
	mov_c_A[3] = 3;
	mov_c_A[4] = 4;

	mov_c_b = A[3];
	mov_c_A[5] = b;

	check(mov_c_A[0] == 0);
	check(mov_c_A[1] == 1);
	check(mov_c_A[2] == 2);
	check(mov_c_A[3] == 3);
	check(mov_c_A[4] == 4);
	check(mov_c_b == 3);
	check(mov_c_A[5] == 3);

	return 0;
}
// unalign_

volatile unsigned unalign_x = 0xffffffff;
volatile unsigned char unalign_buf[16];

int unalign_main() {

	for(int i = 0; i < 4; i++) {
		*((volatile unsigned*)(unalign_buf + 3)) = 0xaabbccdd;

		unalign_x = *((volatile unsigned*)(unalign_buf + 3));
		check(unalign_x == 0xaabbccdd);

		unalign_buf[0] = unalign_buf[1] = 0;
	}

	return 0;
}
// select_sort_

#define select_sort_N 20

int select_sort_a[select_sort_N] = {2, 12, 14, 6, 13, 15, 16, 10, 0, 18, 11, 19, 9, 1, 7, 5, 4, 3, 8, 17};

void select_sort_select_sort() {
	int i, j, k, t;
	for(i = 0; i < select_sort_N - 1; i ++) {
		k = i;
		for(j = i + 1; j < select_sort_N; j ++) {
			if(select_sort_a[j] < select_sort_a[k]) {
				k = j;
			}
		}

		t = select_sort_a[i];
		select_sort_a[i] = select_sort_a[k];
		select_sort_a[k] = t;
	}
}

int select_sort_main() {
	select_sort_select_sort();

	int i;
	for(i = 0; i < select_sort_N; i ++) {
		check(select_sort_a[i] == i);
	}

	check(i == select_sort_N);

	select_sort_select_sort();

	for(i = 0; i < select_sort_N; i ++) {
		check(select_sort_a[i] == i);
	}

	check(i == select_sort_N);

	return 0;
}
// mul_longlong_

long long mul_longlong_mul(long long a,long long b) {
	long long ans = a*b;
	return ans;
}

int mul_longlong_test_data[] = { 0xaeb1c2aa, 0x4500ff2b, 0x877190af, 0x11f42438};
long long mul_longlong_ans[] = { 0x19d29ab9db1a18e4LL, 0xea15986d3ac3088eLL, 0x2649e980fc0db236LL, 0xfa4c43da0a4a7d30LL, 0x1299898e2c56b139LL, 0xdf8123d50a319e65LL, 0x4d6dfa84c15dd68LL, 0x38c5d79b9e4357a1LL, 0xf78b91cb1efc4248LL, 0x14255a47fdfcc40LL};

#define mul_longlong_NR_DATA LENGTH(test_data)

int mul_longlong_main() {
	int i,j,ans_idx = 0;
	for (i = 0;i < mul_longlong_NR_DATA;i++) {
		for (j = i;j < mul_longlong_NR_DATA;j++) {
			check(mul_longlong_ans[ans_idx++] == mul(mul_longlong_test_data[i],mul_longlong_test_data[j]));
		}
		check(j == mul_longlong_NR_DATA);
	}

	check(i == mul_longlong_NR_DATA);

	return 0;
}

// load_store_

unsigned short load_store_mem[] = {
	0x0, 0x0258, 0x4abc, 0x7fff, 0x8000, 0x8100, 0xabcd, 0xffff
};

unsigned load_store_lh_ans[] = {
	0x00000000, 0x00000258, 0x00004abc, 0x00007fff, 0xffff8000, 0xffff8100, 0xffffabcd, 0xffffffff
};

unsigned load_store_lhu_ans[] = {
	0x00000000, 0x00000258, 0x00004abc, 0x00007fff, 0x00008000, 0x00008100, 0x0000abcd, 0x0000ffff
};

unsigned  load_store_sh_ans[] = {
	0x0000fffd, 0x0000fff7, 0x0000ffdf, 0x0000ff7f, 0x0000fdff, 0x0000f7ff, 0x0000dfff, 0x00007fff
};

unsigned  load_store_lwlr_ans[] = {
	0xbc025800, 0x7fff4a, 0xcd810080, 0xffffab
};

int load_store_main() {
	unsigned i;

	for(i = 0; i < LENGTH(load_store_mem); i ++) {
		check((short)load_store_mem[i] == load_store_lh_ans[i]);
	}

	for(i = 0; i < LENGTH(load_store_mem); i ++) {
		check(load_store_mem[i] == load_store_lhu_ans[i]);
	}

	for(i = 0; i < ((LENGTH(load_store_mem) / 2) - 1); i ++) {
		unsigned x = ((unsigned*)((void*)load_store_mem + 1))[i];
		check(x == load_store_lwlr_ans[i]);
	}

	for(i = 0; i < LENGTH(load_store_mem); i ++) {
		load_store_mem[i] = ~(1 << (2 * i + 1));
		check(load_store_mem[i] == load_store_sh_ans[i]);
	}

	return 0;
}
// fact_

int fact_f[15];
int fact_ans[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600};

int fact_fact(int n) {
	if(n == 0 || n == 1) return 1;
	else return fact_fact(n - 1) * n;
}

int fact_main() {
	int i;
	for(i = 0; i < 13; i ++) {
		fact_f[i] = fact_fact(i);
		check(fact_f[i] == fact_ans[i]);
	}

	return 0;
}

// prime_

int prime_ans[] = {101, 103, 107, 109, 113, 127, 131, 137, 139, 149};

int prime_main() {
	int m, i, n = 0;
	int prime;
	for(m = 101; m <= 150; m += 2) {
		prime = 1;
		for(i = 2; i < m; i ++) {
			if(m % i == 0) {
				prime = 0;
				break;
			}
		}
		if(prime) {
			check(i == prime_ans[n]);
			n ++;
		}
	}

	check(n == 10);

	return 0;
}
// pascal_

#define pascal_N 31

int pascal_a[pascal_N];
int pascal_ans[] = {1, 30, 435, 4060, 27405, 142506, 593775, 2035800, 5852925, 14307150, 30045015, 54627300, 86493225, 119759850, 145422675, 155117520, 145422675, 119759850, 86493225, 54627300, 30045015, 14307150, 5852925, 2035800, 593775, 142506, 27405, 4060, 435, 30, 1};

int pascal_main() {
	int i, j;
	int t0, t1;
	pascal_a[0] = pascal_a[1] = 1;

	for(i = 2; i < pascal_N; i ++) {
		t0 = 1;
		for(j = 1; j < i; j ++) {
			t1 = pascal_a[j];
			pascal_a[j] = t0 + t1;
			t0 = t1;
		}
		pascal_a[i] = 1;
	}

	for(j = 0; j < pascal_N; j ++) {
		check(pascal_a[j] == pascal_ans[j]);
	}

	check(j == pascal_N);

	return 0;
}
// string_

char *string_s[] = {
	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
	", World!\n",
	"Hello, World!\n",
	"#####"
};

char string_str1[] = "Hello";
char string_str[20];

int main() {
	check(rt_strcmp(string_s[0], string_s[2]) == 0);
	check(rt_strcmp(string_s[0], string_s[1]) < 0);
	check(rt_strcmp(string_s[0] + 1, string_s[1] + 1) < 0);
	check(rt_strcmp(string_s[0] + 2, string_s[1] + 2) < 0);
	check(rt_strcmp(string_s[0] + 3, string_s[1] + 3) < 0);

	// check(strcmp( strcat(strcpy(str, str1), s[3]), s[4]) == 0);

	check(rt_memcmp(rt_memset(string_str, '#', 5), string_s[5], 5) == 0);

	return 0;
}
// add_

int add_add(int a, int b) {
	int c = a + b;
	return c;
}

int add_test_data[] = {0, 1, 2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff};
int add_ans[] = {0, 0x1, 0x2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff, 0x1, 0x2, 0x3, 0x80000000, 0x80000001, 0x80000002, 0xffffffff, 0, 0x2, 0x3, 0x4, 0x80000001, 0x80000002, 0x80000003, 0, 0x1, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff, 0, 0x7ffffffd, 0x7ffffffe, 0x80000000, 0x80000001, 0x80000002, 0xffffffff, 0, 0x1, 0x7ffffffe, 0x7fffffff, 0x80000001, 0x80000002, 0x80000003, 0, 0x1, 0x2, 0x7fffffff, 0x80000000, 0xfffffffe, 0xffffffff, 0, 0x7ffffffd, 0x7ffffffe, 0x7fffffff, 0xfffffffc, 0xfffffffd, 0xffffffff, 0, 0x1, 0x7ffffffe, 0x7fffffff, 0x80000000, 0xfffffffd, 0xfffffffe};

#define add_NR_DATA LENGTH(add_test_data)

int add_main() {
	int i, j, ans_idx = 0;
	for(i = 0; i < add_NR_DATA; i ++) {
		for(j = 0; j < add_NR_DATA; j ++) {
			check(add_add(add_test_data[i], add_test_data[j]) == add_ans[ans_idx ++]);
		}
		check(j == add_NR_DATA);
	}

	check(i == add_NR_DATA);

	return 0;
}
// bit_

typedef unsigned char uint8_t;
__attribute__((noinline))
bool bit_getbit(void *buf, int offset){
	int byte = offset >> 3;
	offset &= 7;
	uint8_t mask = 1 << offset;
	return (((uint8_t *)buf)[byte] & mask) != 0;
}
__attribute__((noinline))
void bit_setbit(void *buf, int offset, bool bit){
	int byte = offset >> 3;
	offset &= 7;
	uint8_t mask = 1 << offset;

	uint8_t * volatile p = buf + byte;
	*p = (bit == 0 ? (*p & ~mask) : (*p | mask));
}

int bit_main() {
	uint8_t buf[2];

	buf[0] = 0xaa;
	buf[1] = 0x0;
	check(getbit(buf, 0) == 0);
	check(getbit(buf, 1) == 1);
	check(getbit(buf, 2) == 0);
	check(getbit(buf, 3) == 1);
	check(getbit(buf, 4) == 0);
	check(getbit(buf, 5) == 1);
	check(getbit(buf, 6) == 0);
	check(getbit(buf, 7) == 1);

	setbit(buf, 8, 1);
	setbit(buf, 9, 0);
	setbit(buf, 10, 1);
	setbit(buf, 11, 0);
	setbit(buf, 12, 1);
	setbit(buf, 13, 0);
	setbit(buf, 14, 1);
	setbit(buf, 15, 0);
	check(buf[1] == 0x55);

	return 0;
}
// add_longlong_

long long add_longlong_add(long long a, long long b) {
	long long c = a + b;
	return c;
}

long long add_longlong_test_data[] = {0, 1, 2, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL};
long long add_longlong_ans[] = {0LL, 0x1LL, 0x2LL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL, 0x1LL, 0x2LL, 0x3LL, 0x8000000000000000LL, 0x8000000000000001LL, 0x8000000000000002LL, 0xffffffffffffffffLL, 0LL, 0x2LL, 0x3LL, 0x4LL, 0x8000000000000001LL, 0x8000000000000002LL, 0x8000000000000003LL, 0LL, 0x1LL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL, 0LL, 0x7ffffffffffffffdLL, 0x7ffffffffffffffeLL, 0x8000000000000000LL, 0x8000000000000001LL, 0x8000000000000002LL, 0xffffffffffffffffLL, 0LL, 0x1LL, 0x7ffffffffffffffeLL, 0x7fffffffffffffffLL, 0x8000000000000001LL, 0x8000000000000002LL, 0x8000000000000003LL, 0LL, 0x1LL, 0x2LL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL, 0LL, 0x7ffffffffffffffdLL, 0x7ffffffffffffffeLL, 0x7fffffffffffffffLL, 0xfffffffffffffffcLL, 0xfffffffffffffffdLL, 0xffffffffffffffffLL, 0LL, 0x1LL, 0x7ffffffffffffffeLL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0xfffffffffffffffdLL, 0xfffffffffffffffeLL};

#define add_longlong_NR_DATA LENGTH(test_data)

int add_longlong_main() {
	int i, j, ans_idx = 0;
	for(i = 0; i < add_longlong_NR_DATA; i ++) {
		for(j = 0; j < add_longlong_NR_DATA; j ++) {
			check(add_longlong_add(add_longlong_test_data[i], add_longlong_test_data[j]) == add_longlong_ans[ans_idx ++]);
		}
	}

	return 0;
}
// hello_str_

char hello_str_buf[128];

int main() {
	rt_sprintf(hello_str_buf, "%s", "Hello world!\n");
	check(rt_strcmp(hello_str_buf, "Hello world!\n") == 0);

	rt_sprintf(hello_str_buf, "%d + %d = %d\n", 1, 1, 2);
	check(rt_strcmp(hello_str_buf, "1 + 1 = 2\n") == 0);

	rt_sprintf(hello_str_buf, "%d + %d = %d\n", 2, 10, 12);
	check(rt_strcmp(hello_str_buf, "2 + 10 = 12\n") == 0);

	return 0;
}
// switch_

int switch_switch_case(int n) {
	int ret;
	switch(n) {
		case 0: ret = 0; break;
		case 1: ret = 2; break;
		case 2: case 3: ret = 5; break;
		case 4: case 5: case 6: case 7: ret = 8; break;
		case 8: case 9: case 10: case 11: ret = 10; break;
		case 12: ret = 15; break;
		default: ret = -1; break;
	}

	return ret;
}

int switch_ans[] = {-1, 0, 2, 5, 5, 8, 8, 8, 8, 10, 10, 10, 10, 15, -1};

int switch_main() {
	int i;
	for(i = 0; i < 15; i ++) {
		check(switch_switch_case(i - 1) == switch_ans[i]);
	}

	check(i == 15);

	return 0;
}
// leap_year_

int leap_year_is_leap_year(int n) {
	return (n % 4 == 0 && n % 100 != 0) || (n % 400 == 0);
}

int leap_year_ans[] = {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0};

int leap_year_main() {
	int i;
	for(i = 0; i < 125; i ++) {
		check(leap_year_is_leap_year(i + 1890) == leap_year_ans[i]);
	}

	return 0;
}
// goldbach_

int goldbach_is_prime(int n) {
	if(n < 2) return 0;

	int i;
	for(i = 2; i < n; i ++) {
		if(n % i == 0) {
			return 0;
		}
	}

	return 1;
}

int goldbach_goldbach(int n) {
	int i;
	for(i = 2; i < n; i ++) {
		if(goldbach_is_prime(i) && goldbach_is_prime(n - i)) {
			return 1;
		}
	}

	return 0;
}

int goldbach_main() {
	int n;
	for(n = 4; n <= 30; n += 2) {
		check(goldbach_goldbach(n) == 1);
	}

	return 0;
}
// sum_

int sum_main() {
	int i = 1;
	volatile int sum = 0;
	while(i <= 100) {
		sum += i;
		i ++;
	}

	check(sum == 5050);

	return 0;
}
// if_else_

int if_else_if_else(int n) {
	int cost;
	if(n > 500) cost = 150;
	else if(n > 300) cost = 100;
	else if(n > 100) cost = 75;
	else if(n > 50) cost = 50;
	else cost = 0;

	return cost;
}

int if_else_test_data[] = {-1, 0, 49, 50, 51, 99, 100, 101, 299, 300, 301, 499, 500, 501};
int if_else_ans[] = {0, 0, 0, 0, 50, 50, 50, 75, 75, 75, 100, 100, 100, 150};

#define if_else_NR_DATA LENGTH(test_data)

int if_else_main() {
	int i, ans_idx = 0;
	for(i = 0; i < if_else_NR_DATA; i ++) {
		check(if_else_if_else(if_else_test_data[i]) == if_else_ans[ans_idx ++]);
	}

	check(i == if_else_NR_DATA);

	return 0;
}
